﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Platform.LanguageProcessing.Expressions;
using System.Diagnostics;

namespace Platform.LanguageProcessing
{

	/// <summary>
	/// 
	/// </summary>
	public class Parser
	{

		/// <summary>
		/// 
		/// </summary>
		/// <param name="grammar"></param>
		protected Parser( SyntaxAnalyzer analyzer, Grammar grammar )
		{
			this.Grammar = grammar;
			this.Analyzer = analyzer;
		}

		/// <summary>
		/// 
		/// </summary>
		public Grammar Grammar
		{ get; private set; }

		/// <summary>
		/// 
		/// </summary>
		public SyntaxAnalyzer Analyzer
		{ get; private set; }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="source"></param>
		/// <returns></returns>
		public GrammarExpression Parse( string source )
		{
			Scanner scanner = new Scanner( source );
			ParserContext context = new ParserContext( this.Analyzer, this, scanner );

			while ( !scanner.EndOfText )
			{
				switch ( scanner.Token )
				{
					case TokenType.Period:
						this.ParsePeriod( context );
						break;
					case TokenType.Comma:

						break;
					case TokenType.Word:
						this.ParseWord( scanner.Word, context );
						break;
					default:
						break;
				}

				scanner.NextToken();
			}

			if ( context.Expressions.IsEmpty )
				throw new InvalidOperationException( "Há algo errado. =O" );

			return context.PopSentence();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="word"></param>
		/// <param name="context"></param>
		protected void ParseWord( string word, ParserContext context )
		{
			var bestMatch = this.Grammar.Words.GetBestMatch( word );
			IWordParser wordParser = null;

			// Não encontrou a palavra no dicionário, será que pode ser uma nova palavra?
			if ( bestMatch.Value == null )
			{
				context.Expressions.Push( this.ParseNoun( word, context ) );
			}
			else
			{
				wordParser = bestMatch.Value;
				context.Expressions.Push( wordParser.Parse( word, context ) );
			}
			context.Analyser.Analyze( bestMatch.Key, context );
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="word"></param>
		/// <param name="context"></param>
		/// <returns></returns>
		protected virtual GrammarExpression ParseNoun( string word, ParserContext context )
		{
			return null;
		}


		//protected virtual bool TryParsePreposition( string preposition, ParserContext context )
		//{
		//    // TODO : Validação das preposições
		//    // Adicionar na coleção de erros do parse
		//    // 1. verificar a concordância
		//    // 2. verificar o genero
		//    // 3. verificar o número

		//    if ( this.Grammar.Preposition.Exists( preposition ) )
		//    {
		//        context.Expressions.Push( new PrepositionExpression( preposition ) );
		//        return true;
		//    }
		//    else
		//    {
		//        return false;
		//    }
		//}

		protected virtual void ParsePeriod( ParserContext context )
		{
			//this.ExtractAndPushSubject( context );
			

		}

		// Exemplo, achou uma vírgula
		protected virtual void ParsePause( ParserContext context )
		{

		}

		//protected virtual SubjectExpression ExtractAndPushSubject( ParserContext context )
		//{
		//	if ( context.Expressions.IsEmpty )
		//	{
		//		return null;
		//	}

		//	var subject = context.Expressions.OfType<SubjectExpression>().FirstOrDefault();

		//	if ( subject == null )
		//	{
		//		List<GrammarExpression> part = new List<GrammarExpression>();


		//		foreach ( var ex in context.Expressions )
		//		{

		//		}

		//		//subject = new SubjectExpression( context.PopUntil( e => e is SentenceExpression ) );
		//		//context.Expressions.Push( subject );
		//	}

		//	return subject;
		//}
	}


}
